/* plotter.cpp */

#include <dodo_plot/kernel/plotter.h>
#include <cmath>

namespace dodo_plot
{

void Plotter::begin_new_path() const
{
	cr_->begin_new_path();
}

void Plotter::begin_new_sub_path() const
{
	cr_->begin_new_sub_path();
}

void Plotter::close_path() const
{
	cr_->close_path();
}

//fill & paint
void Plotter::fill() const
{
	cr_->fill();
}

void Plotter::fill_preserve() const
{
	cr_->fill_preserve();
}

void Plotter::paint() const
{
	cr_->paint();
}

//stroke
void Plotter::stroke() const
{
	cr_->stroke();
}

void Plotter::stroke_preserve() const
{
	cr_->stroke_preserve();
}

//move line arc, etc
void Plotter::move_to(double x, double y) const
{
	move_to(Point(x, y));
}

void Plotter::move_to(const Point& p) const
{
	Point actual_point = proj_(p);
	cr_->move_to(actual_point.x, actual_point.y);
}

void Plotter::line_to(double x, double y) const
{
	line_to(Point(x, y));
}

void Plotter::line_to(const Point& p) const
{
	Point actual_point = proj_(p);
	cr_->line_to(actual_point.x, actual_point.y);
}

void Plotter::rel_move_to(double x, double y) const
{
	rel_move_to(Point(x, y));
}

void Plotter::rel_move_to(const Point& offset) const
{
	Point actual_offset = proj_(offset);
	cr_->rel_move_to(actual_offset.x, actual_offset.y);
}

void Plotter::rel_line_to(double x, double y) const
{
	rel_line_to(Point(x, y));
}

void Plotter::rel_line_to(const Point& offset) const
{
	Point actual_offset = proj_(offset);
	cr_->rel_line_to(actual_offset.x, actual_offset.y);
}

void Plotter::abs_move_to(double x, double y) const
{
	cr_->move_to(x, y);
}

void Plotter::abs_move_to(const Point& p) const
{
	cr_->move_to(p.x, p.y);
}

void Plotter::abs_line_to(double x, double y) const
{
	cr_->line_to(x, y);
}

void Plotter::abs_line_to(const Point& p) const
{
	cr_->line_to(p.x, p.y);
}

void Plotter::abs_rel_move_to(double x, double y) const
{
	cr_->rel_move_to(x, y);
}

void Plotter::abs_rel_move_to(const Point& offset) const
{
	cr_->rel_move_to(offset.x, offset.y);
}

void Plotter::abs_rel_line_to(double x, double y) const
{
	cr_->rel_line_to(x, y);
}

void Plotter::abs_rel_line_to(const Point& offset) const
{
	cr_->rel_line_to(offset.x, offset.y);
}

void Plotter::rectangle(const Position& pos) const
{
	Point p1 = proj_(pos.left, pos.top);
	Point p2 = proj_(pos.right, pos.bottom);
	Position now_pos(p1, p2);
	cr_->rectangle(
		now_pos.left, now_pos.top,
		now_pos.width(), now_pos.height()
		);
}

void Plotter::rectangle(const Point& topleft, double w, double h) const
{
	rectangle(Position(topleft.x, topleft.x + w, topleft.y, topleft.y + h));
}

void Plotter::rectangle(const Point& p1, const Point& p2) const
{
	rectangle(Position(p1, p2));
}

void Plotter::abs_rectangle(const Position& pos) const
{
	cr_->rectangle(pos.left, pos.top, pos.width(), pos.height());
}

void Plotter::abs_rectangle(const Point& topleft, double w, double h) const
{
	abs_rectangle(Position(topleft.x, topleft.x + w, topleft.y, topleft.y + h));
}

void Plotter::abs_rectangle(const Point& p1, const Point& p2) const
{
	abs_rectangle(Position(p1, p2));
}
//font & text
void Plotter::set_font(const Font& font) const
{
	cr_->set_font_face(font.font_face());
}

void Plotter::set_font_size(double size) const
{
	cr_->set_font_size(size);
}

void Plotter::show_text(const std::string& text) const
{
	cr_->show_text(text);
}

//
Point Plotter::get_current_point() const
{
	double x, y;
	cr_->get_current_point(x, y);
	return Point(x, y);
}

void Plotter::clip() const
{
	cr_->clip();
}

void Plotter::reset_clip() const
{
	cr_->reset_clip();
}

void Plotter::rotate(double rad_degrees) const
{
	cr_->rotate(rad_degrees);
}

void Plotter::rotate_degrees(double degrees) const
{
	cr_->rotate_degrees(degrees);
}
//
//line
void Plotter::set_line_width(double width) const
{
	cr_->set_line_width(width);
}

void Plotter::set_line_cap(LineCap mode) const
{
	cr_->set_line_cap(mode);
}

void Plotter::set_line_join(LineJoin mode) const
{
	cr_->set_line_join(mode);
}

//source
void Plotter::set_color(const Color& color) const
{
	cr_->set_source_rgba(color.r(),
		color.g(),
		color.b(),
		color.a()
		);
}
//	void Plotter::set_source();
//
void Plotter::save() const
{
	cr_->save();
}

void Plotter::restore() const
{
	cr_->restore();
}

Context_p Plotter::get_cr() const
{
	return cr_;
}

Plotter Plotter::sub_plotter(const Position& sub_pos, const Position& sub_local_pos) const
{
	return Plotter(cr_, 
		Position(
			proj_(sub_pos.left, sub_pos.top), 
			proj_(sub_pos.right, sub_pos.bottom)
			),
		sub_local_pos
		);
}

Point Plotter::get_abs_point(double x, double y) const
{
	return proj_(x, y);
}

Point Plotter::get_abs_point(const Point& point) const
{
	return proj_(point);
}

Plotter::Plotter(Context_p cr, const Position& given_pos, const Position& local_pos)
	: cr_(cr), proj_(Pos_Projection(given_pos, local_pos))
{ }

//Extra functions
void Plotter::line(const Point& p1, const Point& p2) const
{
	move_to(p1);
	line_to(p2);
}

void Plotter::move_to_direction(double absolute_length, double degree) const
{
	// Notice: this function takes the length as absolute length.
	// and the degree to the north is 0, to the east is 90, etc
	cr_->rel_move_to(absolute_length * cos(degree), -absolute_length * sin(degree));
}

void Plotter::line_to_direction(double absolute_length, double degree) const
{
	// Notice: this function takes the length as absolute length.
	// and the degree to the north is 0, to the east is 90, etc
	cr_->rel_line_to(absolute_length * cos(degree), -absolute_length * sin(degree));
}

}
